#include "Id4MapLexer.hpp"
#include "Vectors.hpp"
#include "SceneNode.hpp"
#include "ChcSceneManager.hpp"
#include "Engine.hpp"
#include "OpenGL.hpp"
#include "Window.hpp"
#include "Input.hpp"
#include "Camera.hpp"
#include "FpsCameraControl.hpp"
#include "Mesh.hpp"
#include "QuakeMeshLoaders.hpp"

#include <boost/scoped_array.hpp>
#include <boost/foreach.hpp>
#include <fstream>

#define foreach BOOST_FOREACH

using namespace cge;

class Game: public Engine, public InputListener {
public:
	Game() {
		getLog().addDevice( new StreamLogDevice(std::cout) );

		win_.reset     ( new Window( *this ) );
		inp_.reset     ( new Input( *this ) );
		scene_.reset   ( new ChcSceneManager(*this) );
		
		VideoMode vm(800,800,32);
		vm.setDecorated(false);
		win_->setVideoMode( vm );
		
		addTask( *win_ );
		addTask( *inp_ );

		win_->addTask( *scene_ );
		inp_->addInputListener(*this);

		setupGL();
		createCamera();
		createLevel();
	}

	void setupGL() {
		glDepthFunc(GL_LEQUAL);
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		glEnable(GL_CULL_FACE);
		glCullFace( GL_FRONT );
		glEnable( GL_COLOR_MATERIAL );
	}

	void createCamera() {
		cam_.reset( new Camera() );
		ctrl_.reset( new FpsCameraControl(*inp_, *cam_) );
		cam_->setProjection( 90.0, (double)win_->getWidth() / win_->getHeight(), 0.1, 128.0 );
		scene_->getRoot().createChild()->attachEntity( *cam_ );
		scene_->setCamera(*cam_);

		ctrl_->connect();
	}

	void createLevel() {
		std::ifstream ifs("../../data/level2.bsp", std::ios::binary);
		assert( ifs.is_open() );
		SceneNode *n = scene_->getRoot().createChild();
		n->setRotation( Quaternion(-3.1415926538/2.0,0.0,0.0) );
		n->attachEntity( *(new Mesh( BspMeshLoader(ifs) )) );
	}

	void onClose() {
		die("User exit.");
	}

	void onKeyPressed( KeyEvent &ev ) {
		if( ev.getCode() == 27 )
			die("User exit.");
	}


public:
	std::auto_ptr<SceneManager>     scene_;
	std::auto_ptr<Input>            inp_;
	std::auto_ptr<Window>           win_;
	std::auto_ptr<Camera>           cam_;
	std::auto_ptr<FpsCameraControl> ctrl_;
};


int main(int argc, char *argv[]) {
	{
		Game g;
		g.start();
	}
	std::cin.get();
	return 0;
}
